#include "get_weather.h"

// 生成HTTP请求的函数
char *Weather_Http_Request()
{
    char city[20] = "\0";

    // 使用静态分配的字符数组来存储HTTP请求
    static char request[1024] = "GET /v3/weather/now.json?key=SAewqnjWlC7dvMLfL&location=guangzhou&language=zh-Hans&unit=c HTTP/1.1\r\nHost:api.seniverse.com\r\n\r\n";

    return request;
}

// 解析HTTP响应的函数
void parse(char *res, int *ok, int *len)
{
    char *retcode = res + strlen("HTTP/1.x ");

    // 根据HTTP状态码判断请求是否成功
    switch (atoi(retcode))
    {
    case 200 ... 299:
        *ok = 1;
        printf("查询成功\n");
        break;

    case 400 ... 499:
        *ok = 0;
        printf("客户端错误\n");

    case 500 ... 599:
        *ok = 0;
        printf("服务端错误\n");
    }

    // 解析Content-Length头部，获取响应正文的长度
    char *p;
    if (p = strstr(res, "Content-Length: "))
    {
        *len = atoi(p + strlen("Content-Length: "));
    }
}

char *get_weather()
{
    // 根据域名通过DNS查询函数获取IP
    struct hostent *host_inf = gethostbyname("api.seniverse.com");
    if (host_inf == (struct hostent *)NULL)
    {
        perror("gethostbyname ... ");
        return (char *)-1;
    }
    // printf("IP:%s\n", inet_ntoa((*(struct in_addr *)host_inf->h_addr_list[0])));

    // 创建套接字
    int cli_fd = socket(AF_INET, SOCK_STREAM, 0);
    if (cli_fd == -1)
    {
        perror("socket ...");
        return (char *)-1;
    }
    struct sockaddr_in ser_inf;
    memset(&ser_inf, 0, sizeof(ser_inf));

    ser_inf.sin_family = AF_INET;
    ser_inf.sin_port = htons(80);
    ser_inf.sin_addr.s_addr = inet_addr(inet_ntoa((*(struct in_addr *)host_inf->h_addr_list[0])));

    // 连接服务器
    if (connect(cli_fd, (struct sockaddr *)&ser_inf, sizeof(ser_inf)) == -1)
    {
        perror("connect ...");
        return (char *)-1;
    }

    printf("连接服务器成功！\n");

    // 调用write函数发送请求报文  ---
    char *req = Weather_Http_Request();
    // printf("%s\n", req);

    if (write(cli_fd, req, strlen(req)) == -1)
    {
        perror("write ...");
        return (char *)-1;
    }

    // 调用read函数接收响应报文：响应行+响应头部（ Content-Length:）
    char res[1024] = "\0"; // 存放状态行+响应头部
    int total = 0;
    while (1)
    {
        int n = read(cli_fd, res + total, 1); // 一个一个字节的接收

        if (n <= 0)
        {
            perror("读取HTTP头部失败");
            return (char *)-1;
        }

        total += n;

        if (strstr(res, "\r\n\r\n")) // 如果第一次出现\r\n\r\n则表明状体行+响应头部已经接收完成，跳出for循环
            break;
    }

    // 解析状态码判断是否查询成功，如果成功则获取后面要读取的响应包体的大小
    int ok = 0;
    int len = 0;
    // res:响应行+响应头部
    // ok:1 或者0 查询成功与否
    // len:到时候是存放响应包体的大小
    parse(res, &ok, &len);
    if (!ok)
    {
        printf("查询失败\n");
        return (char *)-1;
    }

    // printf("响应包体大小：%d\n", len);

    // 调用read函数在读取响应包体
    char *data = (char *)malloc(sizeof(char) * len);
    if (data == (char *)NULL)
    {
        perror("malloc ...");
        return (char *)-1;
    }

    memset(data, 0, sizeof(char) * len);

    if (read(cli_fd, data, len) == -1)
    {
        perror("Read ...");
        return (char *)-1;
    }

    cJSON *root = cJSON_Parse(data); // 把网络json数据转成C语言的json

    // 解析json数据
    cJSON *body = cJSON_GetObjectItem(root, "results");
    cJSON *a = cJSON_GetArrayItem(body, 0);
    cJSON *now = cJSON_GetObjectItem(a, "now");

    const char *weather = cJSON_GetObjectItem(now, "text")->valuestring;
    const char *temp = cJSON_GetObjectItem(now, "temperature")->valuestring;

    // printf("weather: %s\n", weather);
    // printf("temp: %s°C\n", temp);

    // 构建返回的天气信息字符串
    char *weather_info = malloc(strlen(weather) + strlen(temp) + 20);
    sprintf(weather_info, "Weather: %s, Temp: %s°C", weather, temp);

    // free释放json对象
    free(root);
    free(data);

    // 关闭套接字
    if (close(cli_fd) == -1)
    {
        perror("close ...");
        return (char *)-1;
    }

    return weather_info;
}
